#include <string.h>
#include <stdio.h>
#include "air105.h"

//#define DMA_RX 1
#define DMA_TX 1
#define DMA_BLOCK_SIZE 4
#define BUFF_SIZE 128

void UART_Configuration(void);
void DMA_Configuration(void);

uint8_t src_Buf[BUFF_SIZE] = {0};
uint8_t dst_Buf[BUFF_SIZE] = {0};

UART_TypeDef *UARTx = UART0;

int main(void)
{
	uint32_t i, index = 0;
	SYSCTRL_ClocksTypeDef clocks;
	SYSCTRL_PLLConfig(SYSCTRL_PLL_204MHz);					  // 设置PLL时钟
	SYSCTRL_GetClocksFreq(&clocks);							  // 获取时钟频率
	SYSCTRL_AHBPeriphClockCmd(SYSCTRL_AHBPeriph_DMA, ENABLE); // 使能DMA时钟
	SYSCTRL_AHBPeriphResetCmd(SYSCTRL_AHBPeriph_DMA, ENABLE); // 复位DMA

	SYSCTRL_APBPeriphClockCmd(SYSCTRL_APBPeriph_UART0 | SYSCTRL_APBPeriph_UART1 | SYSCTRL_APBPeriph_GPIO, ENABLE); // 使能UART0、UART1、GPIO时钟
	SYSCTRL_APBPeriphResetCmd(SYSCTRL_APBPeriph_UART0 | SYSCTRL_APBPeriph_UART1, ENABLE);						   // 复位UART0、UART1

	UART_Configuration(); // 配置UART
	DMA_Configuration();  // 配置DMA
	printf("LuatOS AIR105 UART DMA Demo V1.0.\r\n");

#ifdef DMA_RX
	while (1)
	{
		DMA_ChannelCmd(DMA_Channel_3, ENABLE);// 使能DMA通道
		while (RESET == DMA_GetRawStatus(DMA_Channel_3, DMA_IT_BlockTransferComplete))// 等待DMA传输完成
			;
		DMA_ClearITPendingBit(DMA_Channel_3, DMA_IT_BlockTransferComplete);// 清除DMA传输完成中断标志
		DMA_SetDSRAddress(DMA_Channel_3, (uint32_t)&dst_Buf[0]);// 设置DMA目的地址
		for (index = 0; index < DMA_BLOCK_SIZE; index++)// 打印接收到的数据
			printf("%c", dst_Buf[index]);
	}
#endif

#ifdef DMA_TX
	for (index = 0; index < sizeof(src_Buf) / sizeof(src_Buf[0]); index++) // 初始化发送缓冲区
		src_Buf[index] = index;

	DMA_ChannelCmd(DMA_Channel_3, ENABLE);			 // 使能DMA通道
	for (i = 0; i < BUFF_SIZE / DMA_BLOCK_SIZE; i++) // 循环发送
	{
		while (DMA_IsChannelEnabled(DMA_Channel_3) != DISABLE) // 等待DMA通道空闲
			;
		DMA_ChannelCmd(DMA_Channel_3, ENABLE); // 使能DMA通道
	}

	while (1)
	{
	}
#endif
}

void UART_Configuration(void)
{
	UART_InitTypeDef UART_InitStructure;
	UART_FIFOInitTypeDef UART_FIFOInitStruct;

	GPIO_PinRemapConfig(GPIOA, GPIO_Pin_0 | GPIO_Pin_1, GPIO_Remap_0); // UART0_TXD、UART0_RXD引脚重映射

	UART_StructInit(&UART_InitStructure);	   // 初始化UART结构体
	UART_FIFOStructInit(&UART_FIFOInitStruct); // 初始化UART FIFO结构体

	UART_InitStructure.UART_BaudRate = 115200;
	UART_InitStructure.UART_WordLength = UART_WordLength_8b;
	UART_InitStructure.UART_StopBits = UART_StopBits_1;
	UART_InitStructure.UART_Parity = UART_Parity_No;

	UART_FIFOInitStruct.FIFO_Enable = ENABLE;							 // 使能FIFO
	UART_FIFOInitStruct.FIFO_DMA_Mode = UART_FIFO_DMA_Mode_0;			 // DMA模式0
	UART_FIFOInitStruct.FIFO_RX_Trigger = UART_FIFO_RX_Trigger_1_4_Full; // 接收FIFO触发水平为1/4
	UART_FIFOInitStruct.FIFO_TX_Trigger = UART_FIFO_TX_Trigger_1_4_Full; // 发送FIFO触发水平为1/4
	UART_FIFOInitStruct.FIFO_TX_TriggerIntEnable = ENABLE;				 // 使能发送FIFO触发中断

	UART_Init(UART0, &UART_InitStructure);		// 初始化UART
	UART_FIFOInit(UART0, &UART_FIFOInitStruct); // 初始化UART FIFO
}

void DMA_Configuration(void)
{
	DMA_InitTypeDef DMA_InitStruct;

#ifdef DMA_RX
	DMA_InitStruct.DMA_DIR = DMA_DIR_Peripheral_To_Memory;// DMA传输方向：外设到内存
	DMA_InitStruct.DMA_Peripheral = (uint32_t)UART0;// 外设地址
	DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t) & (UART0->OFFSET_0.RBR);// 外设数据寄存器地址
	DMA_InitStruct.DMA_PeripheralInc = DMA_Inc_Nochange;// 外设地址不变
	DMA_InitStruct.DMA_PeripheralDataSize = DMA_DataSize_Byte;// 外设数据宽度为8位
	DMA_InitStruct.DMA_PeripheralBurstSize = DMA_BurstSize_1;// 外设突发传输大小为1
	DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)&dst_Buf[0];// 内存地址
	DMA_InitStruct.DMA_MemoryInc = DMA_Inc_Increment;// 内存地址自增
	DMA_InitStruct.DMA_MemoryDataSize = DMA_DataSize_Byte;// 内存数据宽度为8位
	DMA_InitStruct.DMA_MemoryBurstSize = DMA_BurstSize_1;// 内存突发传输大小为1
	DMA_InitStruct.DMA_BlockSize = DMA_BLOCK_SIZE;// DMA传输块大小
	DMA_InitStruct.DMA_PeripheralHandShake = DMA_PeripheralHandShake_Hardware;// 外设硬件握手
#endif

#ifdef DMA_TX
	DMA_InitStruct.DMA_DIR = DMA_DIR_Memory_To_Peripheral;						// 内存到外设
	DMA_InitStruct.DMA_Peripheral = (uint32_t)UARTx;							// 外设地址
	DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t) & (UARTx->OFFSET_0.THR); // 外设数据寄存器地址
	DMA_InitStruct.DMA_PeripheralInc = DMA_Inc_Nochange;						// 外设地址不变
	DMA_InitStruct.DMA_PeripheralDataSize = DMA_DataSize_Byte;					// 外设数据宽度为8位
	DMA_InitStruct.DMA_PeripheralBurstSize = DMA_BurstSize_8;					// 外设突发传输大小为8
	DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)&src_Buf[0];					// 内存地址
	DMA_InitStruct.DMA_MemoryInc = DMA_Inc_Increment;							// 内存地址自增
	DMA_InitStruct.DMA_MemoryDataSize = DMA_DataSize_Byte;						// 内存数据宽度为8位
	DMA_InitStruct.DMA_MemoryBurstSize = DMA_BurstSize_8;						// 内存突发传输大小为8
	DMA_InitStruct.DMA_BlockSize = DMA_BLOCK_SIZE;								// 传输数据块大小
	DMA_InitStruct.DMA_PeripheralHandShake = DMA_PeripheralHandShake_Hardware;	// 外设硬件请求
#endif

	DMA_Init(DMA_Channel_3, &DMA_InitStruct); // 初始化DMA通道
}

// 串口重定向
int SER_PutChar(int ch)
{
	while (!UART_IsTXEmpty(UARTx))
		;
	UART_SendData(UARTx, (uint8_t)ch);

	return ch;
}
// 串口重定向
int fputc(int c, FILE *f)
{
	/* Place your implementation of fputc here */
	/* e.g. write a character to the USART */
	if (c == '\n')
	{
		SER_PutChar('\r');
	}
	return (SER_PutChar(c));
}

#ifdef USE_FULL_ASSERT

/**
 * @brief  Reports the name of the source file and the source line number
 *         where the assert_param error has occurred.
 * @param  file: pointer to the source file name
 * @param  line: assert_param error line source number
 * @retval None
 */
void assert_failed(uint8_t *file, uint32_t line)
{
	/* User can add his own implementation to report the file name and line number,
	 ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

	/* Infinite loop */
	while (1)
	{
	}
}
#endif
